//===- toyc.cpp - The Toy Compiler ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the entry point for the Toy compiler.
//
//===----------------------------------------------------------------------===//

#include "mlir/IR/Attributes.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/FunctionSupport.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/Verifier.h"
#include <vector>
#include "toy/Dialect.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/Support/raw_ostream.h"

int main() {
  // 创建mlir上下文
  mlir::MLIRContext context;
  // 加载toy方言
  context.getOrLoadDialect<mlir::toy::ToyDialect>();
  // 创建ir生成器
  mlir::OpBuilder builder(&context);
  // 创建一个模块，一个模块类似于一个cpp文件
  mlir::ModuleOp theModule = mlir::ModuleOp::create(builder.getUnknownLoc());
  

  // 创建函数的参数类型，参数数量为2,类型为形状未知的tensor
  llvm::SmallVector<mlir::Type, 4> arg_types(
      2, mlir::UnrankedTensorType::get(builder.getF64Type()));
  // 生成没有返回值的函数类型
  auto func_type = builder.getFunctionType(arg_types, llvm::None);
  // 位置信息对象（所在文件名hello.cpp、行1、列2）
  mlir::Location location =
      builder.getFileLineColLoc(builder.getIdentifier("hello.mlir"), 1, 2);
  // 创建main函数
  auto func = mlir::FuncOp::create(location, "main", func_type);

  // 创建函数入口块
  auto &entryBlock = *func.addEntryBlock();
  // 设置ir插入点为入口块，之后builder对象创建的ir都会创建在这个入口块中
  builder.setInsertionPointToStart(&entryBlock);

  // 创建constOp的output类型
  auto tensorType = mlir::RankedTensorType::get({2, 3}, builder.getF64Type());
  // 创建constOp的input类型
  auto dataType = mlir::RankedTensorType::get({2, 3}, builder.getF64Type());
  // 创建constOp的input
  auto dataAttribute = mlir::DenseElementsAttr::get(
      dataType, llvm::makeArrayRef(std::vector<double>{1,2,3,4,5,6}));

  // 创建第一个constop
  mlir::Location location1 =
      builder.getFileLineColLoc(builder.getIdentifier("hello.mlir"), 2, 1);
  mlir::Value const1 = builder.create<mlir::toy::ConstantOp>(
      location1, tensorType, dataAttribute);

  mlir::Location location2 =
      builder.getFileLineColLoc(builder.getIdentifier("hello.mlir"), 3, 1);
  mlir::Value const2 = builder.create<mlir::toy::ConstantOp>(
      location1, tensorType, dataAttribute);

  // 创建retop
  mlir::Location location3 =
      builder.getFileLineColLoc(builder.getIdentifier("hello.mlir"), 4, 1);
  builder.create<mlir::toy::ReturnOp>(location3,const2);

  // 修改函数返回值类型为tensor
  func.setType(builder.getFunctionType(func.getType().getInputs(),const2.getType()));

  theModule.push_back(func);

  // 验证ir语法是否正确
  if (failed(mlir::verify(theModule))) {
    theModule.emitError("module verification error");
    return 0;
  }
  // 打印当前模块的ir
  theModule.dump();
}